//
//  DeviceExt.swift
//  kano
//
//  Created by Sophia on 2024/8/14.
//

import UIKit
import Photos
import AssetsLibrary
import KeychainAccess
import AdSupport
import AppTrackingTransparency
import CoreTelephony
import MachO
import SystemConfiguration.CaptiveNetwork
import Network

extension UIDevice {
        
    public class var ka_UUID: String {
        let keychain = Keychain(service: "keychain_uuid")
        if let zuid = try? keychain.getString(Bundle.main.bundleIdentifier!) {
            return zuid
        }
        var newZuid = ""
        if let uuid = CFUUIDCreate(nil) {
            let uuidStr = CFUUIDCreateString(nil, uuid)
            if let uuidStringRef = uuidStr {
                newZuid = "\(uuidStringRef)_123420240710"
                newZuid = newZuid.lowercased().replacingOccurrences(of: "-", with: "")
            }
        }
        keychain[Bundle.main.bundleIdentifier!] = newZuid
        return newZuid
    }
    
    public class var ka_judgeCaptureDeviceAuthorize: Bool {
        var var_isAuth = true
        let var_status = AVCaptureDevice.authorizationStatus(for: .video)
        switch var_status {
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { granted in
                if granted {
                    DispatchQueue.main.async {
                        var_isAuth = true
                    }
                } else {
                    DispatchQueue.main.async {
                        var_isAuth = false
                    }
                }
            }
        case .authorized:
            var_isAuth = true
        case .denied:
            fallthrough
        case .restricted:
            var_isAuth = false
            let var_alertView = UIAlertView(title: "Tip", message: "Please allow access to your camera in the Settings - Privacy - Camera option on your phone", delegate: nil, cancelButtonTitle: "I know", otherButtonTitles: "")
            var_alertView.show()
        default:
            break
        }
        return var_isAuth
    }
    
    
    public class var ka_currentWindow: UIWindow {
        let var_window : UIWindow
        if #available(iOS 13.0, *) {
            let var_set = UIApplication.shared.connectedScenes
            let var_windowScene : UIWindowScene = var_set.first as! UIWindowScene
            var_window = var_windowScene.windows.first! as UIWindow
        } else  {
            var_window = UIApplication.shared.windows.first!
        }
        return var_window
    }
   
    public class var ka_statusBarHeight: CGFloat {
        if #available(iOS 13.0, *) {
            let var_set : NSSet = UIApplication.shared.connectedScenes as NSSet
            let var_windowScene :UIWindowScene = var_set.anyObject() as! UIWindowScene
            let var_statusBarManager : UIStatusBarManager = var_windowScene.statusBarManager!
            return var_statusBarManager.statusBarFrame.size.height
        } else {
            return UIApplication.shared.statusBarFrame.size.height
        }
    }
    

    // MARK: - safe Area
    public class var ka_safeTop: CGFloat {
        if #available(iOS 11.0, *) {
            return UIDevice.ka_currentWindow.safeAreaInsets.top
        } else {
            return UIDevice.ka_statusBarHeight
        }
    }

    public class var ka_safeBottom: CGFloat {
        if #available(iOS 11.0, *) {
            return UIDevice.ka_currentWindow.safeAreaInsets.bottom
        } else {
            return 0
        }
    }

    public class var ka_navBarHeight: CGFloat {
        return 44.0;
    }

    public class var ka_tabBarHeight: CGFloat {
        return 49.0;
    }


    //MARK: ---- To use
    public class var ka_screenHeight: CGFloat {
        return UIScreen.main.bounds.size.height
    }
    
    public class var ka_fullNavHeight: CGFloat {
        return UIDevice.ka_safeTop + UIDevice.ka_navBarHeight
    }
    
    public class var ka_fullTabHeight: CGFloat {
        return UIDevice.ka_safeBottom + UIDevice.ka_tabBarHeight
    }

    /// home no navbar,has tabbar
    public class var ka_noNavHeight: CGFloat {
        return UIDevice.ka_screenHeight - UIDevice.ka_fullTabHeight
    }

    /// home has navbar and tabbar
    public class var ka_homeHeight: CGFloat {
        let var_screenHeight : CGFloat = UIScreen.main.bounds.size.height
        return var_screenHeight - UIDevice.ka_fullNavHeight - UIDevice.ka_fullTabHeight
    }

    /// no tabbar ,has navbar
    public class var ka_viewHeight: CGFloat {
        let var_screenHeight : CGFloat = UIScreen.main.bounds.size.height
        return var_screenHeight - UIDevice.ka_fullNavHeight
    }
    
    
//    class func ka_Idfa() -> String {
//        var idfa: String?
//        if #available(iOS 14, *) {
//            if ATTrackingManager.trackingAuthorizationStatus == .authorized {
//                idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
//            }
//        } else {
//            if ASIdentifierManager.shared().isAdvertisingTrackingEnabled {
//                idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
//            }
//        }
//        if idfa == nil || idfa == "00000000-0000-0000-0000-000000000000" {
//            idfa = UIDevice.current.identifierForVendor?.uuidString
//        }
//        return idfa ?? ""
//    }
    //广告标识符 App Tracking Transparency (ATT) 框架的权限： 从 iOS 14.5 开始，应用必须请求用户同意（通过 ATT 的 requestTrackingAuthorization）才能访问 IDFA,如果用户未同意，IDFA 的值将是全零。 如果用户允许广告跟踪，advertisingIdentifier 的值通常是固定的，在设备上安装的所有应用中都是相同的，直到用户手动重置广告标识符。
    class func ka_Idfa() -> String {
        return ASIdentifierManager.shared().advertisingIdentifier.uuidString
    }
    
    //identifierForVendor 是一个为同一个开发者（Vendor）生成的唯一标识符。Vendor 是指共享同一反向域名前缀的应用。例如，com.example.app1 和 com.example.app2 属于同一 Vendor，因为它们的反向域名前缀相同。
    //1.如果用户卸载了应用并重新安装，identifierForVendor 的值会 发生变化。2.如果设备上还有同一 Vendor 的其他应用未被卸载，identifierForVendor 会保持一致。3.在不同设备上，identifierForVendor 会有所不同，即使应用来自同一 Vendor。
    class func ka_Idfv() -> String {
        return UIDevice.current.identifierForVendor?.uuidString ?? ""
    }
    
    class func isIpad() -> String {
        let ispad = UIDevice.current.userInterfaceIdiom == .pad
        if ispad {
            return "1"
        } else {
            return "0"
        }
    }

    
    class func isSimulator() -> Bool {
        #if targetEnvironment(simulator)
        return true
        #else
        return false
        #endif
    }
    
    class func isOpenVPN() -> Bool {
        return false
        var flag = false
        let version = UIDevice.current.systemVersion
        if let versionDouble = Double(version), versionDouble >= 9.0 {
            if let dict = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as? [String: Any],
               let scopedDict = dict["__SCOPED__"] as? [String: Any] {
                let keys = scopedDict.keys
                for key in keys {
                    if key.contains("tap") || key.contains("tun") || key.contains("ipsec") || key.contains("ppp") {
                        flag = true
                        break
                    }
                }
            }
        } else {
            var interfaces: UnsafeMutablePointer<ifaddrs>? = nil
            var tempAddr: UnsafeMutablePointer<ifaddrs>? = nil
            let success = getifaddrs(&interfaces)
            if success == 0 {
                tempAddr = interfaces
                while tempAddr != nil {
                    let string = String(cString: tempAddr!.pointee.ifa_name)
                    if string.contains("tap") || string.contains("tun") || string.contains("ipsec") || string.contains("ppp") {
                        flag = true
                        break
                    }
                    tempAddr = tempAddr!.pointee.ifa_next
                }
            }
            freeifaddrs(interfaces)
        }
        return flag
    }
    
    class func kaProxyStatus() -> Bool {
        if let proxySettings = CFNetworkCopySystemProxySettings()?.takeUnretainedValue() as? [String: Any],
           let proxies = CFNetworkCopyProxiesForURL(URL(string: "https://www.baidu.com")! as CFURL, proxySettings as CFDictionary).takeUnretainedValue() as? [[String: Any]] {
            let settings = proxies[0]
            print("host=\(settings[kCFProxyHostNameKey as String] as? String ?? "")")
            print("port=\(settings[kCFProxyPortNumberKey as String] as? Int ?? 0)")
            print("type=\(settings[kCFProxyTypeKey as String] as? String ?? "")")
            if let proxyType = settings[kCFProxyTypeKey as String] as? String, proxyType == "kCFProxyTypeNone" {
                return false
            } else {
                return true
            }
        }
        return false
    }
    
    class func ka_isCharging() -> String {
        let device = UIDevice.current
        if device.batteryState == .charging || device.batteryState == .full {
            return "true"
        } else {
            return "false"
        }
    }
    
    class func totalDiskSpace() -> String {
        var buf = statfs()
        var totalspace: Int64 = 0
        if statfs("/private/var", &buf) >= 0 {
            totalspace = Int64(buf.f_bsize) * Int64(buf.f_blocks)
        }
        return "\(totalspace)"
    }
    
    class func ka_getSysInfo(by typeSpecifier: UnsafePointer<CChar>) -> String? {
        var size: size_t = 0
        
        // First call to get the size
        sysctlbyname(typeSpecifier, nil, &size, nil, 0)
        
        // Allocate memory for the result
        let answer = UnsafeMutablePointer<CChar>.allocate(capacity: size)
        defer { answer.deallocate() } // Ensure memory is deallocated

        // Second call to get the actual value
        sysctlbyname(typeSpecifier, answer, &size, nil, 0)
        
        // Convert to Swift String
        let results = String(cString: answer)
        return results
    }
    
    class func ka_platform() -> String {
        return ka_getSysInfo(by: "hw.machine") ?? "iPhone"
    }
    
    class func phoneModel() -> String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8 , value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        
        switch identifier {
        case "iPod5,1":                                 return "iPod Touch 5"
        case "iPod7,1":                                 return "iPod Touch 6"
        case "iPhone3,1", "iPhone3,2", "iPhone3,3":     return "iPhone 4"
        case "iPhone4,1":                               return "iPhone 4s"
        case "iPhone5,1", "iPhone5,2":                  return "iPhone 5"
        case "iPhone5,3", "iPhone5,4":                  return "iPhone 5c"
        case "iPhone6,1", "iPhone6,2":                  return "iPhone 5s"
        case "iPhone7,2":                               return "iPhone 6"
        case "iPhone7,1":                               return "iPhone 6 Plus"
        case "iPhone8,1":                               return "iPhone 6s"
        case "iPhone8,2":                               return "iPhone 6s Plus"
        case "iPhone8,4":                               return "iPhone SE (1st generation)"
        case "iPhone9,1", "iPhone9,3":                  return "iPhone 7"
        case "iPhone9,2", "iPhone9,4":                  return "iPhone 7 Plus"
        case "iPhone10,1", "iPhone10,4":                return "iPhone 8"
        case "iPhone10,5", "iPhone10,2":                return "iPhone 8 Plus"
        case "iPhone10,3", "iPhone10,6":                return "iPhone X"
        case "iPhone11,2":                              return "iPhone XS"
        case "iPhone11,4", "iPhone11,6":                return "iPhone XS MAX"
        case "iPhone11,8":                              return "iPhone XR"
        case "iPhone12,1":                              return "iPhone 11"
        case "iPhone12,3":                              return "iPhone 11 pro"
        case "iPhone12,5":                              return "iPhone 11 Pro Max"
        case "iPhone12,8":                              return "iPhone SE (2nd generation)"
        case "iPhone13,1":                              return "iPhone 12 mini"
        case "iPhone13,2":                              return "iPhone 12"
        case "iPhone13,3":                              return "iPhone 12 Pro"
        case "iPhone13,4":                              return "iPhone 12 Pro Max"
        case "iPhone14,4":                              return "iPhone 13 mini"
        case "iPhone14,5":                              return "iPhone 13"
        case "iPhone14,2":                              return "iPhone 13 Pro"
        case "iPhone14,3":                              return "iPhone 13 Pro Max"
        case "iPhone14,6":                              return "iPhone SE (3rd generation)"
        case "iPhone14,7":                              return "iPhone 14"
        case "iPhone14,8":                              return "iPhone 14 Plus"
        case "iPhone15,2":                              return "iPhone 14 Pro"
        case "iPhone15,3":                              return "iPhone 14 Pro Max"
        case "iPhone15,4":                              return "iPhone 15"
        case "iPhone15,5":                              return "iPhone 15 Plus"
        case "iPhone16,1":                              return "iPhone 15 Pro"
        case "iPhone16,2":                              return "iPhone 15 Pro Max"
        case "iPhone17,3":                              return "iPhone 16"
        case "iPhone17,4":                              return "iPhone 16 Plus"
        case "iPhone17,1":                              return "iPhone 16 Pro"
        case "iPhone17,2":                              return "iPhone 16 Pro Max"
            
        case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
        case "iPad3,1", "iPad3,2", "iPad3,3":           return "iPad 3"
        case "iPad3,4", "iPad3,5", "iPad3,6":           return "iPad 4"
        case "iPad6,11", "iPad6,12":                    return "iPad 5"
        case "iPad7,5", "iPad7,6":                      return "iPad 6"
        case "iPad7,11", "iPad7,12":                    return "iPad 7"
        case "iPad11,6", "iPad11,7":                    return "iPad 8"
        case "iPad12,1", "iPad12,2":                    return "iPad 9"
        case "iPad13,18", "iPad13,19":                    return "iPad 10"

        case "iPad4,1", "iPad4,2", "iPad4,3":           return "iPad Air"
        case "iPad5,3", "iPad5,4":                      return "iPad Air 2"
        case "iPad11,3", "iPad11,4":                    return "iPad Air 3"
        case "iPad13,1", "iPad13,2":                    return "iPad Air 4"
        case "iPad13,16", "iPad13,17":                  return "iPad Air 5"
        
        case "iPad2,5", "iPad2,6", "iPad2,7":           return "iPad Mini"
        case "iPad4,4", "iPad4,5", "iPad4,6":           return "iPad Mini 2"
        case "iPad4,7", "iPad4,8", "iPad4,9":           return "iPad Mini 3"
        case "iPad5,1", "iPad5,2":                      return "iPad Mini 4"
        case "iPad11,1", "iPad11,2":                    return "iPad Mini 5"
        case "iPad14,1", "iPad14,2":                    return "iPad Mini 6"
        case "iPad16,1", "iPad16,2":                    return "iPad Mini 7"

        case "iPad6,7", "iPad6,8", "iPad6,3", "iPad6,4", "iPad7,1", "iPad7,2", "iPad7,3", "iPad7,4", "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4", "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8", "iPad8,9", "iPad8,10", "iPad8,11", "iPad8,12", "iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7", "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11", "iPad16,3", "iPad16,4", "iPad16,5", "iPad16,6":         return "iPad Pro"
        case "i386", "x86_64":                          return "Simulator"
        default:                                        return identifier
        }
    }
    
    class func ka_devicePhoneNum() -> String {
        return UserDefaults.standard.string(forKey: "SBFormattedPhoneNumber") ?? ""
    }
    
   
    class func ka_networkType() -> String {
        var strNetworkType = ""
        
        var zeroAddress = sockaddr()
        memset(&zeroAddress, 0, MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sa_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sa_family = sa_family_t(AF_INET)
        
        guard let defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else {
            return strNetworkType
        }
        var flags: SCNetworkReachabilityFlags = []
        let didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags)
        
        if !didRetrieveFlags {
            return strNetworkType
        }
        
        if flags.contains(.connectionRequired) == false {
            strNetworkType = "WIFI"
        }
        
        if flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic) {
            if flags.contains(.interventionRequired) == false {
                strNetworkType = "WIFI"
            }
        }
        
        if flags.contains(.isWWAN) {
            if let info = CTTelephonyNetworkInfo().serviceCurrentRadioAccessTechnology {
                if info.values.contains(where: { $0 == CTRadioAccessTechnologyLTE }) {
                    strNetworkType = "4G"
                } else if info.values.contains(where: { $0 == CTRadioAccessTechnologyEdge || $0 == CTRadioAccessTechnologyGPRS || $0 == CTRadioAccessTechnologyCDMA1x }) {
                    strNetworkType = "2G"
                } else if info.values.contains(where: { $0 == CTRadioAccessTechnologyNRNSA || $0 == CTRadioAccessTechnologyNR }) {
                    strNetworkType = "5G"
                } else if info.values.contains(where: { $0 == CTRadioAccessTechnologyWCDMA || $0 == CTRadioAccessTechnologyHSDPA || $0 == CTRadioAccessTechnologyHSUPA || $0 == CTRadioAccessTechnologyCDMAEVDORev0 || $0 == CTRadioAccessTechnologyCDMAEVDORevA || $0 == CTRadioAccessTechnologyCDMAEVDORevB}) {
                    strNetworkType = "3G"
                }
            }
        }
        
        if strNetworkType.isEmpty {
            strNetworkType = "WWAN"
        }
        
        return strNetworkType
    }
    
//    @available(iOS 14.1, *)
//    func ka_networkType() -> String {
//        let monitor = NWPathMonitor()
//        let queue = DispatchQueue(label: "NetworkMonitor")
//        
//        monitor.pathUpdateHandler = { path in
//            if path.status == .satisfied {
//                if path.usesInterfaceType(.wifi) {
//                    print("当前连接的网络类型是 Wi-Fi")
//                } else if path.usesInterfaceType(.cellular) {
//                    print("当前连接的网络类型是 蜂窝数据")
//                    let networkInfo = CTTelephonyNetworkInfo()
//                    
//                    if let radioAccessTechnology = networkInfo.serviceCurrentRadioAccessTechnology?.values.first {
//                        switch radioAccessTechnology {
//                        case CTRadioAccessTechnologyGPRS, CTRadioAccessTechnologyEdge:
//                            print("当前为 2G 网络")
//                        case CTRadioAccessTechnologyWCDMA, CTRadioAccessTechnologyHSDPA, CTRadioAccessTechnologyHSUPA, CTRadioAccessTechnologyCDMA1x, CTRadioAccessTechnologyCDMAEVDORev0, CTRadioAccessTechnologyCDMAEVDORevA, CTRadioAccessTechnologyCDMAEVDORevB:
//                            print("当前为 3G 网络")
//                        case CTRadioAccessTechnologyLTE:
//                            print("当前为 4G 网络")
//                        case CTRadioAccessTechnologyNRNSA, CTRadioAccessTechnologyNR:
//                            print("当前为 5G 网络")
//                        default:
//                            print("未知蜂窝网络类型")
//                        }
//                    } else {
//                        print("未连接到蜂窝网络")
//                    }
//                }
//            } else {
//                print("没有网络连接")
//            }
//        }
//        
//        monitor.start(queue: queue)
//    }
    
    class func ka_carrierName() -> String {
        let telephonyInfo = CTTelephonyNetworkInfo()
        if let carrierDict = telephonyInfo.serviceSubscriberCellularProviders, let carrier = carrierDict.values.first {
            return carrier.carrierName ?? ""
        } else {
            return ""
        }
    }
     
//    class func screenInches() -> String {
//        let screenSize = UIScreen.main.currentMode?.size ?? CGSize.zero
//        
//        switch screenSize {
//        case CGSize(width: 640, height: 960):
//            return "3.5"
//        case CGSize(width: 640, height: 1136):
//            return "4.0"
//        case CGSize(width: 750, height: 1334):
//            return "4.7"
//        case CGSize(width: 1242, height: 2208):
//            return "5.5"
//        case CGSize(width: 828, height: 1792):
//            return "6.1"
//        case CGSize(width: 1125, height: 2436):
//            return "5.8"
//        case CGSize(width: 1242, height: 2688):
//            return "6.5"
//        case CGSize(width: 1170, height: 2532),
//             CGSize(width: 1179, height: 2556):
//            return "6.1"
//        case CGSize(width: 1284, height: 2778),
//             CGSize(width: 1290, height: 2796):
//            return "6.7"
//        case CGSize(width: 1080, height: 2340):
//            return "5.4"
//        default:
//            return "7.9"
//        }
//    }
    class func screenInches() -> String {
        let screenSize = UIScreen.main.currentMode?.size ?? CGSize.zero
        
        switch screenSize {
        case CGSize(width: 640, height: 960):
            return "3.5" // iPhone 4/4S
        case CGSize(width: 640, height: 1136):
            return "4.0" // iPhone 5/5C/5S/SE
        case CGSize(width: 750, height: 1334):
            return "4.7" // iPhone 6/6S/7/8
        case CGSize(width: 750, height: 1624):
            return "4.7" // iPhone 11 xr zoom
        case CGSize(width: 1125, height: 2001):
            return "4.7" // iPhone 678 zoom
        case CGSize(width: 1242, height: 2208):
            return "5.5" // iPhone 6+/6S+/7+/8+
        case CGSize(width: 828, height: 1792):
            return "6.1" // iPhone XR/11
        case CGSize(width: 1125, height: 2436):
            return "5.8" // iPhone X/XS/11 Pro
        case CGSize(width: 1242, height: 2688):
            return "6.5" // iPhone XS Max/11 Pro Max
        case CGSize(width: 1170, height: 2532):
            return "6.1" // iPhone 12/12 Pro
        case CGSize(width: 1284, height: 2778):
            return "6.7" // iPhone 12 Pro Max/13promax/14plus
        case CGSize(width: 1080, height: 2340):
            return "5.4" // iPhone 12 mini
        case CGSize(width: 1179, height: 2556):
            return "6.1" // iPhone14/14Pro/15/15Pro
        case CGSize(width: 1290, height: 2796):
            return "6.7" // iPhone 14Pro max/15plus/15pro max
        default:
            return "7.9" //Unknown model and ipad
        }
    }
    
    class func ka_batteryInfo() -> String {
        UIDevice.current.isBatteryMonitoringEnabled = true
        let batteryLevel = UIDevice.current.batteryLevel
        let originalString = String(format: "%.0f%%", abs(batteryLevel) * 100.0)
        return originalString
//        //对%做url编码处理，否则数据会有问题
//        let allowedCharacters = CharacterSet.urlQueryAllowed
//        let encodedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacters) ?? ""
//        //print("Encoded String: \(encodedString)")
//        return encodedString
    }
    
    class func ka_Freespace() -> String {
        var hostInfo = vm_statistics64()
        var count = UInt32(MemoryLayout<vm_statistics64_data_t>.stride / MemoryLayout<integer_t>.stride)
        
        let result = withUnsafeMutablePointer(to: &hostInfo) {
            $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
                host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &count)
            }
        }
        if result != KERN_SUCCESS {
            return "0"
        }
        let pageSize = vm_kernel_page_size
        let freeMemory = Double(hostInfo.free_count) * Double(pageSize)
        let inactiveMemory = Double(hostInfo.inactive_count) * Double(pageSize)
        let speculativeMemory = Double(hostInfo.speculative_count) * Double(pageSize)
        
        return "\(Int(freeMemory))"
    }
}
